package com.xsq.wifi.utils;

import android.util.Log;
import java.io.*;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;

public class PCPClient {
    private static final String TAG = "PCPClient";
    private static final int HEADER_SIZE = 8;
    private static final int MAX_PACKET_SIZE = 1440 * 2;
    private static final int RECONNECT_MAX_RETRY = 3;
    private static final int SOCKET_TIMEOUT = 30000;

    private String destIp;
    private int destPort;
    private byte version;
    private int magicNum;

    private Socket socket;
    private OutputStream outputStream;
    private InputStream inputStream;

    public interface PCPCallback {
        void onProgress(int progress);
        void onSuccess(byte[] response);
        void onFailure(String error);
    }

    public PCPClient(String ip, int port, int magicNum, byte version) {
        this.destIp = ip;
        this.destPort = port;
        this.magicNum = magicNum;
        this.version = version;
    }

    // 基础通信方法
    private void sendData(byte cmd, int value, byte[] bodyData) throws IOException {
        ByteBuffer header = ByteBuffer.allocate(HEADER_SIZE)
                .order(ByteOrder.LITTLE_ENDIAN)
                .put(version)
                .put(cmd)
                .putShort((short) value)
                .putInt(bodyData != null ? bodyData.length : 0);

        outputStream.write(header.array());
        if (bodyData != null && bodyData.length > 0) {
            sendChunkedData(bodyData);
        }
        outputStream.flush();
    }

    private void sendChunkedData(byte[] data) throws IOException {
        int sent = 0;
        while (sent < data.length) {
            int remaining = data.length - sent;
            int chunkSize = Math.min(remaining, MAX_PACKET_SIZE);
            outputStream.write(data, sent, chunkSize);
            sent += chunkSize;
        }
    }

    private byte[] receiveData() throws IOException {
        byte[] headerBytes = new byte[HEADER_SIZE];
        readFully(inputStream, headerBytes);

        ByteBuffer header = ByteBuffer.wrap(headerBytes)
                .order(ByteOrder.LITTLE_ENDIAN);

        byte recvVersion = header.get();
        byte command = header.get();
        short status = header.getShort();
        int dataLength = header.getInt();

        if (recvVersion != version) {
            throw new IOException("Protocol version mismatch");
        }

        if (dataLength > 0) {
            byte[] data = new byte[dataLength];
            readFully(inputStream, data);
            return data;
        }
        return null;
    }

    private void readFully(InputStream in, byte[] buffer) throws IOException {
        int read = 0;
        while (read < buffer.length) {
            int count = in.read(buffer, read, buffer.length - read);
            if (count == -1) {
                throw new EOFException("End of stream reached");
            }
            read += count;
        }
    }

    // 连接管理
    private void connect() throws IOException {
        disconnect();

        socket = new Socket();
        socket.setSoTimeout(SOCKET_TIMEOUT);
        socket.connect(new java.net.InetSocketAddress(destIp, destPort), SOCKET_TIMEOUT);
        outputStream = socket.getOutputStream();
        inputStream = socket.getInputStream();
    }

    private void disconnect() {
        try {
            if (outputStream != null) outputStream.close();
            if (inputStream != null) inputStream.close();
            if (socket != null) socket.close();
        } catch (IOException e) {
            Log.w(TAG, "Error closing connection", e);
        }
    }

    // 公开API
    public void sendCommand(byte cmd, int value, byte[] data, PCPCallback callback) {
        new Thread(() -> {
            int retryCount = 0;
            boolean success = false;

            while (retryCount < RECONNECT_MAX_RETRY && !success) {
                try {
                    connect();
                    sendData(cmd, value, data);

                    byte[] response = receiveData();
                    callback.onSuccess(response);
                    success = true;

                } catch (IOException e) {
                    retryCount++;
                    Log.e(TAG, "Command failed (attempt " + retryCount + "/" + RECONNECT_MAX_RETRY + ")", e);

                    if (retryCount >= RECONNECT_MAX_RETRY) {
                        callback.onFailure("Command failed: " + e.getMessage());
                    } else {
                        try {
                            Thread.sleep(2000); // 等待2秒后重试
                        } catch (InterruptedException ie) {
                            Thread.currentThread().interrupt();
                        }
                    }
                } finally {
                    disconnect();
                }
            }
        }).start();
    }

    // 文件传输专用方法
    public void sendFile(byte cmd, int value, File file, PCPCallback callback) {
        new Thread(() -> {
            int retryCount = 0;
            boolean success = false;

            while (retryCount < RECONNECT_MAX_RETRY && !success) {
                try (FileInputStream fis = new FileInputStream(file)) {
                    connect();

                    // 1. 发送文件信息
                    String fileName = file.getName();
                    sendData((byte)0x31, 0, fileName.getBytes("UTF-8"));
                    receiveData(); // 等待确认

                    // 2. 计算校验和
                    int checksum = calculateChecksum(file);

                    // 3. 分块发送文件内容
                    long fileSize = file.length();
                    long totalSent = 0;
                    byte[] buffer = new byte[MAX_PACKET_SIZE];

                    int bytesRead;
                    while ((bytesRead = fis.read(buffer)) != -1) {
                        sendData(cmd, checksum, Arrays.copyOf(buffer, bytesRead));
                        totalSent += bytesRead;

                        int progress = (int)((totalSent * 100) / fileSize);
                        callback.onProgress(progress);
                    }

                    // 4. 获取最终响应
                    byte[] response = receiveData();
                    callback.onSuccess(response);
                    success = true;

                } catch (IOException e) {
                    retryCount++;
                    Log.e(TAG, "File transfer failed (attempt " + retryCount + "/" + RECONNECT_MAX_RETRY + ")", e);

                    if (retryCount >= RECONNECT_MAX_RETRY) {
                        callback.onFailure("File transfer failed: " + e.getMessage());
                    } else {
                        try {
                            Thread.sleep(2000);
                        } catch (InterruptedException ie) {
                            Thread.currentThread().interrupt();
                        }
                    }
                } finally {
                    disconnect();
                }
            }
        }).start();
    }

    private int calculateChecksum(File file) throws IOException {
        int checksum = 0;
        try (InputStream is = new FileInputStream(file)) {
            byte[] buffer = new byte[8192];
            int bytesRead;
            while ((bytesRead = is.read(buffer)) != -1) {
                for (int i = 0; i < bytesRead; i++) {
                    checksum += buffer[i] & 0xFF;
                }
            }
        }
        return checksum & 0xFFFF;
    }
}